%code requires {
  #include <memory>
  #include <string>
  #include "ast.hpp"
}

%{

#include <iostream>
#include <memory>
#include <string>
#include "ast.hpp"

// 声明 lexer 函数和错误处理函数
int yylex();
void yyerror(std::unique_ptr<BaseAST> &ast, const char *s);

using namespace std;

%}

// 定义 parser 函数和错误处理函数的附加参数
// 我们需要返回一个字符串作为 AST, 所以我们把附加参数定义成字符串的智能指针
// 解析完成后, 我们要手动修改这个参数, 把它设置成解析得到的字符串
%parse-param { std::unique_ptr<BaseAST> &ast }

// yylval 的定义, 我们把它定义成了一个联合体 (union)
// 因为 token 的值有的是字符串指针, 有的是整数
// 之前我们在 lexer 中用到的 str_val 和 int_val 就是在这里被定义的
// 至于为什么要用字符串指针而不直接用 string 或者 unique_ptr<string>?
// 请自行 STFW 在 union 里写一个带析构函数的类会出现什么情况
%union {
  std::string *str_val;
  int int_val;
  BaseAST *ast_val;
  BaseExpAST *expAst_val;
  VarDefAST *varDef_val;
  LinkNodeAST *linkNode_val;
  ExpLinkNodeAST *expLinkNode_val;
  FuncFParamMoreAST *funcFParamLinkNode_val;
  CompUnitAST *comp_unit_val;
  FuncFParamsAST *funcf_params_val;
  FuncFParamAST *funcf_param_val;
}


// lexer 返回的所有 token 种类的声明
// 注意 IDENT 和 INT_CONST 会返回 token 的值, 分别对应 str_val 和 int_val
%token INT VOID RETURN CONST IF ELSE WHERE BREAK CONTINUE
%token <str_val> IDENT
%token <int_val> INT_CONST

// 非终结符的类型定义
%type <ast_val> FuncDef Block Stmt Exp PrimaryExp LOrExp LAndExp LVal
%type <ast_val> EqExp RelExp AddExp MulExp UnaryExp ConstExp ConstDecl InitVal 
%type <ast_val> ConstInitVal Decl BlockItem VarDecl IfElseStmt BreakStmt 
%type <ast_val>  ContinueStmt 
%type <expAst_val> ConstDef WhileStmt 
%type <int_val> Number
%type <str_val> FuncType BType
%type <varDef_val> VarDef
%type <linkNode_val> BlockItemMore VarDefMore ExpMore ConstExpMore ArrDimMore ArrayIndexMore ConstInitValMore InitValMore
%type <expLinkNode_val> ConstDefMore
%type <funcFParamLinkNode_val> FuncFParamMore
%type <comp_unit_val> CompUnit
%type <funcf_params_val> FuncFParams
%type <funcf_param_val> FuncFParam
%%

// 开始符, CompUnit ::= FuncDef, 大括号后声明了解析完成后 parser 要做的事情
// 之前我们定义了 FuncDef 会返回一个 str_val, 也就是字符串指针
// 而 parser 一旦解析完 CompUnit, 就说明所有的 token 都被解析了, 即解析结束了
// 此时我们应该把 FuncDef 返回的结果收集起来, 作为 AST 传给调用 parser 的函数
// $1 指代规则里第一个符号的返回值, 也就是 FuncDef 的返回值

ProgramRoot
  : CompUnit {
    auto prog_root = make_unique<ProgramRootAST>();
    prog_root->head_comp_unit=unique_ptr<BaseAST>($1);
    ast = move(prog_root);
  }
  ;

CompUnit
  : Decl CompUnit {
    auto ast = new CompUnitAST();
    ast->func_def = unique_ptr<BaseAST>($1);
    ast->next = $2;
    $$ = ast;
  }
  | FuncDef CompUnit {
    auto ast = new CompUnitAST();
    ast->func_def = unique_ptr<BaseAST>($1);
    ast->next = $2;
    $$ = ast;
  }
  | %empty {
    $$ = nullptr;
  }
  ;

// FuncDef ::= FuncType IDENT '(' ')' Block;
// 我们这里可以直接写 '(' 和 ')', 因为之前在 lexer 里已经处理了单个字符的情况
// 解析完成后, 把这些符号的结果收集起来, 然后拼成一个新的字符串, 作为结果返回
// $$ 表示非终结符的返回值, 我们可以通过给这个符号赋值的方法来返回结果
// 你可能会问, FuncType, IDENT 之类的结果已经是字符串指针了
// 为什么还要用 unique_ptr 接住它们, 然后再解引用, 把它们拼成另一个字符串指针呢
// 因为所有的字符串指针都是我们 new 出来的, new 出来的内存一定要 delete
// 否则会发生内存泄漏, 而 unique_ptr 这种智能指针可以自动帮我们 delete
// 虽然此处你看不出用 unique_ptr 和手动 delete 的区别, 但当我们定义了 AST 之后
// 这种写法会省下很多内存管理的负担
FuncDef
  // : FuncType IDENT '(' FuncFParams ')' Block {
  : BType IDENT '(' FuncFParams ')' Block {
    auto ast = new FuncDefAST();
    ast->func_type = unique_ptr<string>($1);
    ast->ident = *$2;
    ast->block = unique_ptr<BaseAST>($6);
    auto ps=std::move($4->params);
    for(int i=0;i<ps.size();i++){
      ast->params.push_back(std::move(ps[i]));
    }
    $$ = ast;
  }
  // | FuncType IDENT '(' ')' Block {
  | BType IDENT '(' ')' Block {
    auto ast = new FuncDefAST();
    ast->func_type = unique_ptr<string>($1);
    ast->ident = *unique_ptr<string>($2);
    ast->block = unique_ptr<BaseAST>($5);
    $$ = ast;
  }
  ;

FuncFParams
  : FuncFParam FuncFParamMore {
    auto ast = new FuncFParamsAST();
    ast->params.push_back(unique_ptr<FuncFParamAST>($1));
    auto next_p=unique_ptr<FuncFParamMoreAST>($2);
    while(next_p!=nullptr){
      auto t_next_p=std::move(next_p->next);
      ast->params.push_back(std::move(next_p->current));
      next_p=std::move(t_next_p);
    }
    $$=ast;
  }
  ;

FuncFParamMore
  : ',' FuncFParam FuncFParamMore {
    auto ast=new FuncFParamMoreAST();
    ast->current=unique_ptr<FuncFParamAST>($2);
    ast->next=unique_ptr<FuncFParamMoreAST>($3);
    $$=ast;
  }
  | %empty {
    $$=nullptr;
  }
  ;

FuncFParam
  : BType IDENT {
    auto ast=new FuncFParamAST();
    ast->ident=*$2;
    ast->isArr=false;
    $$=ast;
  }
  | BType IDENT '[' ']' ArrDimMore {
    auto ast=new FuncFParamAST();
    ast->ident=*$2;

    ast->isArr=true;
    auto next_p=unique_ptr<LinkNodeAST>($5);
    while(next_p!=nullptr){
      auto t_next_p=std::move(next_p->next);
      ast->dim_exps.push_back(std::move(next_p->current));
      next_p=std::move(t_next_p);
    }
    $$=ast;
  }
  ;

FuncType
  : INT {
    $$ = new string("INT");
  }
  | VOID {
    $$ = new string("VOID");
  }
  ;

Block
  : '{' BlockItemMore '}' {
    auto ast=new BlockAST();
    auto next_p=unique_ptr<LinkNodeAST>($2);
    while(next_p!=nullptr){
      auto t_next_p=std::move(next_p->next);
      ast->stmts.push_back(std::move(next_p->current));
      next_p=std::move(t_next_p);
    }
    $$=ast;
  }
  ;

BlockItemMore
  : BlockItem BlockItemMore {
    auto ast=new BlockItemMoreAST();
    ast->current=unique_ptr<BaseAST>($1);
    ast->next=unique_ptr<LinkNodeAST>($2);
    $$=ast;
  }
  | %empty {
    $$=nullptr;
  }
  ;


Stmt
  : RETURN Exp ';' {
    auto ast = new StmtAST();
    ast->exp = unique_ptr<BaseAST>($2);
    ast->stype=0;
    $$ = ast;
  }
  | LVal '=' Exp ';' {
    auto ast = new StmtAST();
    ast->exp = unique_ptr<BaseAST>($3);
    ast->stype=1;
    ast->lval=unique_ptr<BaseAST>($1);
    $$ = ast;
  }
  | RETURN ';' {
    auto ast = new StmtAST();
    ast->stype=2;
    $$ = ast;
  }
  | Block {
    auto ast = new StmtAST();
    ast->exp = unique_ptr<BaseAST>($1);
    ast->stype=3;
    $$ = ast;
  }
  | Exp ';' {
    auto ast = new StmtAST();
    ast->exp = unique_ptr<BaseAST>($1);
    ast->stype=4;
    $$ = ast;
  }
  | ';' {
    auto ast = new StmtAST();
    ast->stype=5;
    $$ = ast;
  }
  | IfElseStmt {
    auto ast = new StmtAST();
    ast->stype=6;
    ast->exp=unique_ptr<BaseAST>($1);
    $$ = ast;
  }
  | WhileStmt {
    auto ast = new StmtAST();
    ast->stype=7;
    ast->exp=unique_ptr<BaseAST>($1);
    $$ = ast;
  }
  | BreakStmt {
    auto ast = new StmtAST();
    ast->stype=8;
    ast->exp=unique_ptr<BaseAST>($1);
    $$ = ast;
  }
  | ContinueStmt {
    auto ast = new StmtAST();
    ast->stype=9;
    ast->exp=unique_ptr<BaseAST>($1);
    $$ = ast;
  }
  ;

ContinueStmt
  : CONTINUE ';' {
    auto ast = new ContinueStmtAST();
    $$ = ast;
  } 
  ;

BreakStmt 
  : BREAK ';' {
    auto ast = new BreakStmtAST();
    $$ = ast;
  }
  ;

WhileStmt
  : WHERE '(' Exp ')' Stmt {
    auto ast = new WhileStmtAST(2);
    ast->left_ast=unique_ptr<BaseAST>($3);
    ast->right_ast=unique_ptr<BaseAST>($5);
    $$ = ast;
  }
  ;

IfElseStmt
  : IF '(' Exp ')' Stmt ELSE Stmt{
    auto ast = new IfElseStmtAST(3);
    ast->left_ast=unique_ptr<BaseAST>($3);
    ast->right_ast=unique_ptr<BaseAST>($5);
    ast->more_ast0=unique_ptr<BaseAST>($7);
    $$ = ast;
  }
  | IF '(' Exp ')' Stmt{
    auto ast = new IfElseStmtAST(2);
    ast->left_ast=unique_ptr<BaseAST>($3);
    ast->right_ast=unique_ptr<BaseAST>($5);
    $$ = ast;
  }
  ;

Number
  : INT_CONST {
    $$ = $1;
  }
  ;

Exp
  : LOrExp {
    auto ast = new ExpAST(1);
    ast -> left_ast = unique_ptr<BaseAST>($1);
    $$ = ast;
  }
  ;

PrimaryExp 
  : '(' Exp ')'  {
    auto ast = new PrimaryExpAST(1);
    ast ->left_ast = unique_ptr<BaseAST>($2);
    $$ = ast;
  }
  | LVal {
    auto ast = new PrimaryExpAST(-1);
    ast ->lval = unique_ptr<BaseAST>($1);
    $$ = ast;
  }
  | Number {
    auto ast = new PrimaryExpAST(0);
    ast ->ident = *unique_ptr<string>(new string(to_string($1)));
    $$ = ast;
  }
  ;

UnaryExp
  : PrimaryExp {
    auto ast = new UnaryExpAST(1,'+');
    ast -> left_ast = unique_ptr<BaseAST>($1);
    $$ = ast;
  }
  | '+' UnaryExp {
    auto ast = new UnaryExpAST(1,'+');
    ast -> left_ast = unique_ptr<BaseAST>($2);
    $$ = ast;
  }
  | '-' UnaryExp {
  auto ast = new UnaryExpAST(1,'-');
  ast -> left_ast = unique_ptr<BaseAST>($2);
  $$ = ast;
  }
  | '!' UnaryExp {
  auto ast = new UnaryExpAST(1,'!');
  ast -> left_ast = unique_ptr<BaseAST>($2);
  $$ = ast;
  }
  | IDENT '(' Exp ExpMore ')' {
  auto ast = new UnaryExpAST(-1,'f');
  ast -> real_params.push_back(unique_ptr<BaseAST>($3));
  ast->fun_name=*unique_ptr<std::string>($1);

  auto next_p=unique_ptr<LinkNodeAST>($4);
  while(next_p!=nullptr){
    auto t_next_p=std::move(next_p->next);
    ast -> real_params.push_back(std::move(next_p->current));
    next_p=std::move(t_next_p);
  }

  $$ = ast;
  }
  | IDENT '(' ')' {
  auto ast = new UnaryExpAST(0,'f');
  ast->fun_name=*unique_ptr<std::string>($1);
  $$ = ast;
  }
  ;

ExpMore 
  : ',' Exp ExpMore {
    auto ast=new ExpMoreAST();
    ast->current=unique_ptr<BaseAST>($2);
    ast->next=unique_ptr<LinkNodeAST>($3);
    $$=ast;
  }
  | %empty {
    $$=nullptr;
  }

MulExp 
  :UnaryExp {
    auto ast = new MulExpAST(1);
    ast -> left_ast = unique_ptr<BaseAST>($1);
    $$ = ast;
  }
  | MulExp '*' UnaryExp {
    auto ast = new MulExpAST(2);
    ast -> left_ast = unique_ptr<BaseAST>($1);
    ast -> right_ast = unique_ptr<BaseAST>($3);
    ast -> op = '*';
    $$ = ast;
  }
  | MulExp '/' UnaryExp {
    auto ast = new MulExpAST(2);
    ast -> left_ast = unique_ptr<BaseAST>($1);
    ast -> right_ast = unique_ptr<BaseAST>($3);
    ast -> op = '/';
    $$ = ast;
  }
  | MulExp '%' UnaryExp {
    auto ast = new MulExpAST(2);
    ast -> left_ast = unique_ptr<BaseAST>($1);
    ast -> right_ast = unique_ptr<BaseAST>($3);
    ast -> op = '%';
    $$ = ast;
  }
  ;

AddExp 
  : MulExp {
    auto ast = new AddExpAST(1);
    ast -> left_ast = unique_ptr<BaseAST>($1);
    $$ = ast;
  }
  | AddExp '+' MulExp {
    auto ast = new AddExpAST(2);
    ast -> left_ast = unique_ptr<BaseAST>($1);
    ast -> right_ast = unique_ptr<BaseAST>($3);
    ast ->op='+';
    $$ = ast;
  }
  | AddExp '-' MulExp {
    auto ast = new AddExpAST(2);
    ast -> left_ast = unique_ptr<BaseAST>($1);
    ast -> right_ast = unique_ptr<BaseAST>($3);
    ast ->op='-';
    $$ = ast;
  }
  ;

RelExp
  : AddExp {
    auto ast = new RelExpAST(1);
    ast -> left_ast = unique_ptr<BaseAST>($1);
    $$ = ast;
  }
  | RelExp '<' AddExp {
    auto ast = new RelExpAST(2);
    ast -> left_ast = unique_ptr<BaseAST>($1);
    ast -> right_ast = unique_ptr<BaseAST>($3);
    ast->op="<";
    $$ = ast;
  }
  | RelExp '>' AddExp {
    auto ast = new RelExpAST(2);
    ast -> left_ast = unique_ptr<BaseAST>($1);
    ast -> right_ast = unique_ptr<BaseAST>($3);
    ast->op=">";
    $$ = ast;
  }
  | RelExp '<''=' AddExp {
    auto ast = new RelExpAST(2);
    ast -> left_ast = unique_ptr<BaseAST>($1);
    ast -> right_ast = unique_ptr<BaseAST>($4);
    ast->op="<=";
    $$ = ast;
  }
  | RelExp '>''=' AddExp {
    auto ast = new RelExpAST(2);
    ast -> left_ast = unique_ptr<BaseAST>($1);
    ast -> right_ast = unique_ptr<BaseAST>($4);
    ast->op=">=";
    $$ = ast;
  }
  ;

EqExp
  : RelExp {
    auto ast = new EqExpAST(1);
    ast -> left_ast = unique_ptr<BaseAST>($1);
    $$ = ast;
  }
  | EqExp '=''=' RelExp{
    auto ast = new EqExpAST(2);
    ast -> left_ast = unique_ptr<BaseAST>($1);
    ast -> right_ast = unique_ptr<BaseAST>($4);
    ast->op = "==";
    $$ = ast;
  }
  | EqExp '!''=' RelExp {
    auto ast = new EqExpAST(2);
    ast -> left_ast = unique_ptr<BaseAST>($1);
    ast -> right_ast = unique_ptr<BaseAST>($4);
    ast->op = "!=";
    $$ = ast;
  }
  ;

LAndExp
  : EqExp {
    auto ast = new LAndExpAST(1);
    ast -> left_ast = unique_ptr<BaseAST>($1);
    $$ = ast;
  }
  | LAndExp '&''&' EqExp {
    auto ast = new LAndExpAST(2);
    ast -> left_ast = unique_ptr<BaseAST>($1);
    ast -> right_ast = unique_ptr<BaseAST>($4);
    $$ = ast;
  }
  ;

LOrExp
  : LAndExp {
    auto ast = new LOrExpAST(1);
    ast -> left_ast = unique_ptr<BaseAST>($1);
    $$ = ast;
  }
  | LOrExp '|''|' LAndExp {
    auto ast = new LOrExpAST(2);
    ast -> left_ast = unique_ptr<BaseAST>($1);
    ast -> right_ast = unique_ptr<BaseAST>($4);
    $$ = ast;
  }
  ;

// 常量
BType
  : INT {
    $$=new string("INT");
  }
  | VOID {
    $$=new string("VOID");
  }
  ;


Decl
  : ConstDecl {
    auto ast=new DeclAST();
    ast->next=unique_ptr<BaseAST>($1);
    $$=ast;
  }
  | VarDecl {
    auto ast=new DeclAST();
    ast->next=unique_ptr<BaseAST>($1);
    $$=ast;
  }
  ;

ConstDecl 
    : CONST BType ConstDef ConstDefMore ';' {
    auto ast = new ConstDeclAST();
    ast -> cons.push_back(unique_ptr<BaseExpAST>($3));
    auto next_p=unique_ptr<ExpLinkNodeAST>($4);
    while(next_p!=nullptr){
      auto t_next_p=std::move(next_p->next);
      ast->cons.push_back(std::move(next_p->current));
      next_p=std::move(t_next_p);
    }
    $$ = ast;
  }
  ;

ConstDefMore
  : ',' ConstDef ConstDefMore {
    auto ast=new ConstDefMoreAST();
    ast->current=unique_ptr<BaseExpAST>($2);
    ast->next=unique_ptr<ExpLinkNodeAST>($3);
    $$=ast;

  }
  | %empty {
    $$=nullptr;
  }
  ;

ConstDef
  : IDENT '=' ConstInitVal {
    auto ast = new ConstDefAST(0);
    ast->ident=*unique_ptr<string>($1);
    ast -> left_ast = unique_ptr<BaseAST>($3);
    ast->isArr=false;
    $$ = ast;
  }
  | IDENT ArrDimMore '=' ConstInitVal {
    auto ast = new ConstDefAST(1);
    ast->ident=*unique_ptr<string>($1);
    ast -> left_ast = unique_ptr<BaseAST>($4);
    ast->isArr=true;

    auto next_p=unique_ptr<LinkNodeAST>($2);
    while(next_p!=nullptr){
      auto t_next_p=std::move(next_p->next);
      ast->dim_exps.push_back(std::move(next_p->current));
      next_p=std::move(t_next_p);
    }

    $$ = ast;
  }
  ;

ConstInitVal
  : ConstExp {
    auto ast = new ConstInitValAST(0);
    ast -> left_ast = unique_ptr<BaseAST>($1);
    ast->isArr=false;
    $$ = ast;
  }
  | '{'  '}' {
    auto ast = new ConstInitValAST(1);
    ast->isArr=true;
    $$ = ast;
  }
  | '{' ConstInitVal ConstInitValMore '}' {
    auto ast = new ConstInitValAST(1);
    ast->isArr=true;
    ast -> consts.push_back(unique_ptr<BaseAST>($2));

    auto next_p=unique_ptr<LinkNodeAST>($3);
    while(next_p!=nullptr){
      auto t_next_p=std::move(next_p->next);
      ast->consts.push_back(std::move(next_p->current));
      next_p=std::move(t_next_p);
    }

    $$ = ast;
  }
  ;

ConstInitValMore
  : ',' ConstInitVal ConstInitValMore {
    auto ast = new ConstInitValMoreAST();
    ast->current=unique_ptr<BaseAST>($2);
    ast->next=unique_ptr<LinkNodeAST>($3);
    $$=ast;
  }
  | %empty {
    $$=nullptr;
  }
  ;

ConstExpMore
  : ',' ConstExp ConstExpMore {
    auto ast = new ConstExpMoreAST();
    ast->current=unique_ptr<BaseAST>($2);
    ast->next=unique_ptr<LinkNodeAST>($3);
    $$=ast;
  }
  | %empty {
    $$=nullptr;
  }
  ;

VarDecl 
  : BType VarDef VarDefMore ';' {
    auto ast = new VarDeclAST();
    ast->vars.push_back(unique_ptr<VarDefAST>($2));

    auto next_p=unique_ptr<LinkNodeAST>($3);
    while(next_p!=nullptr){
      auto t_next_p=std::move(next_p->next);
      ast->vars.push_back(std::move(next_p->current));
      next_p=std::move(t_next_p);
    }

    $$ = ast;
  }
  ;

VarDefMore
  : ',' VarDef VarDefMore {
    auto ast=new VarDefMoreAST();
    ast->current=unique_ptr<BaseAST>($2);
    ast->next=unique_ptr<LinkNodeAST>($3);
    $$=ast;
  }
  | %empty {
    $$=nullptr;
  }
  ;

VarDef
  : IDENT {
    auto ast = new VarDefAST(0);
    ast->ident=*unique_ptr<string>($1);
    $$ = ast;
  }
  | IDENT '=' InitVal {
    auto ast = new VarDefAST(1);
    ast->ident=*unique_ptr<string>($1);
    ast -> left_ast = unique_ptr<BaseAST>($3);
    $$ = ast;
  }
  | IDENT ArrDimMore {
    auto ast = new VarDefAST(2);
    ast->ident=*unique_ptr<string>($1);
    ast->isArr=true;

    ast->left_ast=unique_ptr<BaseAST>(new InitValAST(1));

    auto next_p=unique_ptr<LinkNodeAST>($2);
    while(next_p!=nullptr){
      auto t_next_p=std::move(next_p->next);
      ast -> dims.push_back(std::move(next_p->current));
      next_p=std::move(t_next_p);
    }

    $$ = ast;
  }
  | IDENT ArrDimMore '=' InitVal {
    auto ast = new VarDefAST(3);
    ast->ident=*unique_ptr<string>($1);
    ast->isArr=true;

    ast->left_ast=unique_ptr<BaseAST>($4);

    auto next_p=unique_ptr<LinkNodeAST>($2);
    while(next_p!=nullptr){
      auto t_next_p=std::move(next_p->next);
      ast -> dims.push_back(std::move(next_p->current));
      next_p=std::move(t_next_p);
    }

    ast->right_ast=unique_ptr<BaseAST>($4);
    $$ = ast;
  }
  ;

ArrDimMore
  : '[' ConstExp ']' ArrDimMore {
    auto ast=new ArrDimMoreAST();
    ast->current=unique_ptr<BaseAST>($2);
    ast->next=unique_ptr<LinkNodeAST>($4);
    $$=ast;
  }
  | %empty {
    $$=nullptr;
  }
  ;

InitVal
  : Exp {
    auto ast = new InitValAST(0);
    ast->left_ast=unique_ptr<BaseAST>($1);
    ast->isArr=false;
    $$=ast;
  }
  | '{' '}' {
    auto ast = new InitValAST(1);
    ast->isArr=true;
    $$=ast;
  }
  | '{' InitVal InitValMore '}' {
    auto ast = new InitValAST(1);
    ast->isArr=true;
    ast -> vals.push_back(unique_ptr<BaseAST>($2));

    auto next_p=unique_ptr<LinkNodeAST>($3);
    while(next_p!=nullptr){
      auto t_next_p=std::move(next_p->next);
      ast -> vals.push_back(std::move(next_p->current));
      next_p=std::move(t_next_p);
    }

    $$ = ast;
  }
  ;

InitValMore
  : ',' InitVal InitValMore {
    auto ast = new InitValMoreAST();
    ast->current=unique_ptr<BaseAST>($2);
    ast->next=unique_ptr<LinkNodeAST>($3);
    $$=ast;
  }
  | %empty {
    $$=nullptr;
  }

BlockItem 
  : Decl {
    auto ast=new BlockItemAST();
    ast->next= unique_ptr<BaseAST>($1);
    $$=ast;
  }
  | Stmt {
    auto ast=new BlockItemAST();
    ast->next= unique_ptr<BaseAST>($1);
    $$=ast;
  }
  ;

LVal
  : IDENT {
    auto ast=new LValAST();
    ast->ident=*unique_ptr<string>($1);
    ast->stype=0;
    ast->isArr=false;
    $$=ast;
  }
  | IDENT ArrayIndexMore {
    auto ast=new LValAST();
    ast->ident=*unique_ptr<string>($1);
    ast->isArr=true;

    auto next_p=unique_ptr<LinkNodeAST>($2);
    while(next_p!=nullptr){
      auto t_next_p=std::move(next_p->next);
      ast -> exps.push_back(std::move(next_p->current));
      next_p=std::move(t_next_p);
    }

    ast->stype=1;
    $$=ast;
  }
  ;

ArrayIndexMore 
  : '[' Exp ']' ArrayIndexMore {
    auto ast=new ArrDimMoreAST();
    ast->current=unique_ptr<BaseAST>($2);
    ast->next=unique_ptr<LinkNodeAST>($4);
    $$=ast;
  }
  | %empty {
    $$=nullptr;
  }
  ;

ConstExp
  : Exp {
    auto ast = new ConstExpAST();
    ast -> left_ast = unique_ptr<BaseAST>($1);
    $$ = ast;
  }
  ;

%%

// 定义错误处理函数, 其中第二个参数是错误信息
// parser 如果发生错误 (例如输入的程序出现了语法错误), 就会调用这个函数
void yyerror(unique_ptr<BaseAST> &ast, const char *s) {
  cerr << "error: " << s << endl;
}
